#include "drv_usb2uart.h"

uint8_t usart_rx_buffer[USART_BUFFER_SIZE];
volatile uint32_t g_uart_tx_transfer_length = 0;

static volatile uint32_t UARTx_Rx_DMACurCount;  /* Serial port 1 receive dma current counter */
static volatile uint32_t UARTx_Rx_DMALastCount; /* Serial port 1 receive dma last value counter  */

volatile uint16_t Rx_RemainLen; /* Remaining unprocessed length of the serial x data receive buffer */

void DMA1_Channel7_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

__attribute__((section(".highcode"))) void DMA1_Channel7_IRQHandler(void)
{
    // 全满
    if (DMA1->INTFR & DMA1_IT_TC7) {
        DMA1->INTFCR = DMA1_IT_TC7;
        chry_dap_usb2uart_uart_send_complete(g_uart_tx_transfer_length);
    }
}

void uartx_preinit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = { 0 };
    USART_InitTypeDef USART_InitStructure = { 0 };
    NVIC_InitTypeDef NVIC_InitStructure = { 0 };

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    /* USART2 TX-->A.2   RX-->A.3 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART2, &USART_InitStructure);
    USART_Cmd(USART2, ENABLE);

    DMA_InitTypeDef DMA_InitStructure = { 0 };
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel7);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR); /* USART2->DATAR:0x40004404 */
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)0;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 0;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel7, &DMA_InitStructure);

    DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE); // 传输完成
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_DeInit(DMA1_Channel6);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)usart_rx_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = USART_BUFFER_SIZE;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);
    DMA_Cmd(DMA1_Channel6, ENABLE); /* USART2 Rx */

    USART_DMACmd(USART2, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
}

void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_coding)
{
    USART_InitTypeDef USART_InitStructure = { 0 };

    // if(line_coding->dwDTERate >= 1500000)
    // {
    //     line_coding->dwDTERate = 1500000;
    // }
    USART_InitStructure.USART_BaudRate = line_coding->dwDTERate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    /* Number of stop bits (0: 1 stop bit; 1: 1.5 stop bits; 2: 2 stop bits). */
    if (line_coding->bCharFormat == 1) {
        USART_InitStructure.USART_StopBits = USART_StopBits_1_5;
    } else if (line_coding->bCharFormat == 2) {
        USART_InitStructure.USART_StopBits = USART_StopBits_2;
    } else {
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
    }
    /* Check digit (0: None; 1: Odd; 2: Even; 3: Mark; 4: Space); */
    if (line_coding->bParityType == 1) {
        USART_InitStructure.USART_Parity = USART_Parity_Odd;
        USART_InitStructure.USART_WordLength = USART_WordLength_9b;
    } else if (line_coding->bParityType == 2) {
        USART_InitStructure.USART_Parity = USART_Parity_Even;
        USART_InitStructure.USART_WordLength = USART_WordLength_9b;
    } else {
        USART_InitStructure.USART_Parity = USART_Parity_No;
    }
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART2, &USART_InitStructure);

    UARTx_Rx_DMACurCount = 0;
    UARTx_Rx_DMALastCount = 0;
    Rx_RemainLen = 0;
    DMA1_Channel6->CFGR &= (uint16_t)(~DMA_CFGR1_EN);
    DMA1_Channel6->CNTR = USART_BUFFER_SIZE;
    DMA1_Channel6->CFGR |= DMA_CFGR1_EN;
}

__attribute__((section(".highcode"))) void chry_dap_usb2uart_rx(void)
{
    uint16_t temp16;

    // 获得DMA当前位置
    UARTx_Rx_DMACurCount = DMA1_Channel6->CNTR;
    // 当前位置和上次位置不一样
    if (UARTx_Rx_DMALastCount != UARTx_Rx_DMACurCount) {
        if (UARTx_Rx_DMALastCount > UARTx_Rx_DMACurCount) {
            // 没有到数组末的情况
            temp16 = UARTx_Rx_DMALastCount - UARTx_Rx_DMACurCount;
        } else {
            // 到数组末的情况, 要加上数组末尾没发送完的
            temp16 = USART_BUFFER_SIZE - UARTx_Rx_DMACurCount;
            temp16 += UARTx_Rx_DMALastCount;
        }
        UARTx_Rx_DMALastCount = UARTx_Rx_DMACurCount;
        // 防止越界,如果产生越界需要加大缓冲区
        NVIC_DisableIRQ(USBFS_IRQn);
        if ((Rx_RemainLen + temp16) > USART_BUFFER_SIZE) {
            //while(1){};
        } else {
            Rx_RemainLen += temp16;
        }
        NVIC_EnableIRQ(USBFS_IRQn);
    }
}

void chry_dap_usb2uart_uart_send_bydma(uint8_t *data, uint16_t len)
{
    if (len <= 0) {
        return;
    }
    g_uart_tx_transfer_length = len;
    // Start DMA
    DMA1_Channel7->CFGR &= (uint16_t)(~DMA_CFGR1_EN);
    DMA1_Channel7->CNTR = g_uart_tx_transfer_length;
    DMA1_Channel7->MADDR = (uint32_t)data;
    DMA1_Channel7->CFGR |= DMA_CFGR1_EN;
}
